﻿/**
 * \file CDynMemPool.h
 * \reversion 0.1
 * \brief 动态内存池，应用于大内存分配的动态内存池
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#ifndef __CDYN__MEM__POOL__H
#define __CDYN__MEM__POOL__H

#include "CSingletonFactory.h"
#include <hash_map>

/// 返回内存池的空闲内存大小
#define __MEM_POOL_FREE_SIZE(pool) (size_t)((pool ? (pool->_pEnd - pool->_pFreeBeg) : 0))

/**
 * \biref 动态内存池的定义
 * \==========================================================================================\
 * \== 设计思想：
 * \== 把需要使用内存池的内存size注册到本内存池，每次需要分配内存时，如果请求的size在本内存池
 * \== 中已经注册了，那么从本内存池中分配内存。
 * \== 
 * \== 数据结构：
 * \== 空闲内存块列表：以内存大小为key，以内存块的第一个空闲内存块地址为value，请求分配从此列
 * \== 表小分配。
 * \== 内存块：是一个地址链表，保存着每一个空闲内存块。
 * \== 内存池：内存池是一个链表，每个池是一个固定大小的内存块（应该是最大内存块的N倍），为所有
 * \== 内存块共享。
 * \== 
 * \== 原理：
 * \== 一个内存池只能由一个内存块去申请，申请之后，在归还之前，这个池只能由申请的内存块来用，
 * \== 使用引用计数的方式，如果计数为0，说明可以释放，把内存池归还内存池链表，可由其它块使用。
 * \==========================================================================================\
 */
class CDynMemPool
	: public CSingletonFactory<CDynMemPool>
{
	friend class CSingletonFactory<CDynMemPool>;

public:
	/// 表示单个内存池是最大对象的多少倍
	enum { __MEM_POOL_MULTIPLE = 500 };
	/// 表示初始化时，内存池的分配个数是块种类的多少倍
	enum { __MEM_POOL_INIT_NUM = 20 };


private:
	/// 链表内存池定义
	struct MemPoolNode
	{
		MemPoolNode()
		{
			_pBeg = NULL;
			_pFreeBeg = NULL;
			_pEnd = NULL;
			_count = 0;
			_pNext = NULL;
		}

		char* _pBeg;						/// 内存池开始地址
		char* _pFreeBeg;					/// 内存池可用内存开始地址
		char* _pEnd;						/// 内存池结束地址
		unsigned int _count;				/// 引用计数
		MemPoolNode* _pNext;				/// 下一个内存池地址
	};

	/// 内存块结点定义
	union MemBlcNode
	{
		MemBlcNode()
		{
			_pFreeListLink = NULL;
		}

		union MemBlcNode *_pFreeListLink;	/// 未分配指向下一个块
		char _ClientData[1];				/// 分配后标识内存指针
	};

	/// 内存块组结点定义
	struct MemBlcGroupNode
	{
		MemBlcGroupNode()
		{
			_pFreeMemBloc = NULL;
			_pMemPool = NULL;
			_pNext = NULL;
		}

		MemBlcNode* _pFreeMemBloc;			/// 第一个未分配的内存块结点
		MemPoolNode* _pMemPool;				/// 本组的内存块属于哪个内存池（在此结构里只有_count有用到）
		MemBlcGroupNode* _pNext;			/// 下一个组结点
	};


private:
	typedef stdext::hash_map<unsigned int, MemBlcGroupNode*> _BLOCK_HASH;
	typedef _BLOCK_HASH::iterator _BLOCK_ITER;


private:
	CDynMemPool();
	~CDynMemPool();


private:
	/// 注册内存块
	bool Register(size_t _MemSize);

	/// 初始化
	bool InitMemPool();

	/// 填充内存块
	bool Refill(size_t size, _BLOCK_ITER& iter);


public:
	/// 申请内存是否在此范围之内
	bool CanAlloc(size_t _size);

	/// 申请一段内存
	void* Allocate(size_t _size);

	/// 释放一段内存
	bool Deallocate(void *p, size_t _size);

	/// 打印各个内存块的使用情况，关机程序时，打印可查询内存泄露
	void PrintMemBlock();

	/// 检查内存块组所有结点
	void LookUpMemBlcGroupNode(size_t _size);


private:

	_BLOCK_HASH m_FreeBlockList;		/// 空闲块列表

	MemPoolNode* m_pFstFreePool;		/// 第一个可用的内存池结点（公用内存池）

	size_t m_PoolSize;					/// 内存池大小
};

#endif	/// __CDYN__MEM__POOL__H
